﻿using System;
using System.Collections.Generic;
using DL.Tools;
using UnityEngine;

namespace DL.FSM
{
    public abstract class StateMachine
    {
        //这是一个继承了BindableProperty类型的IState字段，获取Istate要通过.Value
        public readonly BindableProperty<IState> CurrentState = new();
        protected Dictionary<string, IState> StateTable;
        
        //转换警告是否直接退出转换
        protected bool WarringExit;
        protected bool Init;
        protected bool IsChanging;
        protected bool IsTransition;
        //状态进入时间
        protected float StateStartTime;
        //转换期间再次出现转换状态缓存
        protected  List<IState> TMPState = new();
        
        //动画相关
        protected Animator m_Animator;
        public AnimatorStateInfo AnimatorStateInfo { get; private set; }
        /// <summary>
        /// 动画正在过渡
        /// </summary>
        public bool AnimatorIsInTransition { get; private set; }
        
        /// <summary>
        /// 初始化方法，实现基础的配置导入和状态实例化。建议在子类初始化后执行
        /// </summary>
        protected void Initialize(Transform player, List<Type> states, string defaultState)
        {
            StateTable = new(states.Count);
            foreach (var state in states)
            {
                if (Activator.CreateInstance(state, new object[] { this, 0 }) is IState inst)
                {
                    StateTable.Add(state.Name, inst);
                    Debugger.EO_Log("初始化添加状态:" + state.Name);
                }
            }
            Debugger.EO_Log($"{GetType().Name}状态机初始化成功！持有者:{player.name}");
            ChangeState(GetState(defaultState));
            Debugger.EO_Log($"{GetType().Name}状态机默认状态初始化成功！");
            Init = true;
        }

        /// <summary>
        /// 切换状态的接口API
        /// </summary>
        /// <param name="newState"></param>
        /// <param name="priority"></param>
        public bool ChangeState(IState newState, int priority = 0)
        {
#if UNITY_EDITOR
            // if (IsChanging && !IsTransition)
            // {
            //     Debugger.EO_Log($"同一时间内存在多次转换。传入状态:{newState.name}，可能逻辑出现了问题，请检查！", Color.magenta);
            //     //保存一下
            //     if (!TMPState.Contains(newState))
            //     {
            //         TMPState.Add(newState);
            //     }
            //     return false;
            // }

            if (!IsTransition && newState == CurrentState.Value)
            {
                Debug.LogWarning($"当前状态:{CurrentState.Value.name}。传入相同状态:{newState.name}，可能逻辑出现了问题，请检查！");
                if (WarringExit) return false;
            }
#endif
            if (CurrentState.Value?.priority > priority)
            {
                Debug.LogWarning(
                    $"当前状态:{CurrentState.Value.name}优先级:{CurrentState.Value.priority}.传入状态:{newState.name}优先级:{priority}\n.导致转换状态失败");
                if (WarringExit) return false;
            }
#if UNITY_EDITOR
            Debug.Log($"pre:{CurrentState.Value?.name} ------> {newState.name}");
#endif

            IsChanging = true;
            //检查当前状态是否被用于过渡
            IsTransition = StateTransitionCheck(newState);
            if (IsTransition) return false;
            
            //到这里是真正的转换了
            //有倒霉蛋过来了
            // if (TMPState.Count > 0)
            // {
            //     var statesName = string.Empty;
            //     //newState和缓存状态去比较优先级
            //     foreach (var state in TMPState)
            //     {
            //         //后来的转换还是要比当前执行的优先级高点，List自己就带了一个先后顺序。
            //         //如果存在问题，TMD优先队列伺候
            //         if (newState.priority <= state.priority)
            //         {
            //             newState = state;
            //         }
            //         statesName += state.name + "|";
            //     }
            //     Debugger.EO_Log($"同一时间内存在多转换{statesName}，现在更新状态为{newState.name}", Color.magenta);
            // }
            
            if (CurrentState.Value != null)
            {
#if UNITY_EDITOR
                Debug.Log($"即将离开状态:{CurrentState.Value.name}.开始时间：{StateStartTime},共运行{Time.time - StateStartTime}。准备开始新状态：{newState.name}");
#endif
                CurrentState.Value.Exit();
            }
            newState.Enter();
            CurrentState.Value = newState;
            IsChanging = false;
            IsTransition = false;
            ChangeStateCompleted();
            StateStartTime = Time.time;
            return true;
        }

        /// <summary>
        /// 切换状态的接口API
        /// </summary>
        /// <param name="priority">这次改变状态的优先级</param>
        public bool ChangeState<T>(int priority = 0) where T : IState
        {
            var newStateType = typeof(T);
            var newState = GetState(newStateType);
#if UNITY_EDITOR

            // if (IsChanging && !IsTransition)
            // {
            //     Debugger.EO_Log($"同一时间内存在多次转换。传入状态:{newState.name}，可能逻辑出现了问题，请检查！", Color.magenta);
            //     //保存一下
            //     if (!TMPState.Contains(newState))
            //     {
            //         TMPState.Add(newState);
            //     }
            //     // return false;
            // }

            if (!IsTransition && newState == CurrentState.Value)
            {
                Debug.LogWarning($"当前状态:{CurrentState.Value.name}。传入相同状态:{newState.name}，可能逻辑出现了问题，请检查！");
                if (WarringExit) return false;
            }
#endif
            if (CurrentState.Value?.priority > priority)
            {
                Debug.LogWarning(
                    $"当前状态:{CurrentState.Value.name}优先级:{CurrentState.Value.priority}.传入状态:{newState.name}优先级:{priority}\n.导致转换状态失败");
                if (WarringExit) return false;
            }
#if UNITY_EDITOR
            Debug.Log($"pre:{CurrentState.Value?.name} ------> {newState.name}");
#endif
            // var newState = GetState(newStateType);
            IsChanging = true;
            //检查新状态是否被用于过渡
            IsTransition = StateTransitionCheck(newState);
            if (IsTransition) return false;

            //到这里是真正的转换了
            //有倒霉蛋过来了
            // if (TMPState.Count > 0)
            // {
            //     var statesName = string.Empty;
            //     //newState和缓存状态去比较优先级
            //     foreach (var state in TMPState)
            //     {
            //         //后来的转换还是要比当前执行的优先级高点，List自己就带了一个先后顺序。
            //         //如果存在问题，TMD优先队列伺候
            //         if (newState.priority <= state.priority)
            //         {
            //             newState = state;
            //         }
            //         statesName += state.name + "|";
            //     }
            //     Debugger.EO_Log($"同一时间内存在多转换{statesName}，现在更新状态为{newState.name}", Color.magenta);
            //     //做完了，继续
            //     TMPState.Clear();
            // }

            if (CurrentState.Value != null)
            {
#if UNITY_EDITOR
                Debug.Log(
                    $"即将离开状态:{CurrentState.Value.name}.开始时间：{StateStartTime},共运行{Time.time - StateStartTime}。准备开始新状态：{newState.name}");
#endif
                CurrentState.Value.Exit();
            }
            newState.Enter();
            CurrentState.Value = newState;
            IsChanging = false;
            IsTransition = false;
            ChangeStateCompleted();
            StateStartTime = Time.time;
            return true;
        }

        /// <summary>
        /// 状态过渡检查
        /// </summary>
        public bool StateTransitionCheck(IState state)
        {
            return state.StateTransitionCheck();
        }


        /// <summary>
        /// 状态转换完成时调用
        /// </summary>
        public void ChangeStateCompleted()
        {
            CurrentState.Value.StateTransitionCompleted();
        }

        /// <summary>
        /// 处理输入的接口API
        /// </summary>
        public void HandleInput()
        {
            if(!Init || IsChanging) return; 
            //只允许一个状态在这里更新
            CurrentState.Value.HandleInput();
        }

        public void FixedUpdate()
        {
            if(!Init || IsChanging) return;
            CurrentState.Value.FixedUpdate();
        }

        /// <summary>
        /// 更新非物理逻辑的接口API
        /// </summary>
        public void Update()
        {
            if(!Init || IsChanging) return;
            CurrentState.Value.Update();
        }
        
        /// <summary>
        /// 执行动画RootMotionAPI
        /// </summary>
        public void OnAnimationMove()
        {
            if(!Init || IsChanging) return;
            CurrentState.Value.OnAnimationMove();
        }
        
        /// <summary>
        /// 执行动画事件的接口API
        /// </summary>
        public void OnAnimationTranslateEvent<T>() where T : IState
        {
            if(!Init || IsChanging) return;
            CurrentState.Value.OnAnimationTranslateEvent<T>();
        }
        
        /// <summary>
        /// 状态退出事件
        /// </summary>
        public void OnAnimationExitEvent()
        {
            if(!Init || IsChanging) return;
            CurrentState.Value.OnAnimationExitEvent();
        }

        /// <summary>
        /// 检查更新动画状态机状态，这个方法在初始化完成后工作
        /// </summary>
        public void CheckAnimatorArgs()
        {
            if(!Init) return;
            AnimatorStateInfo = m_Animator.GetCurrentAnimatorStateInfo(0);
            AnimatorIsInTransition = m_Animator.IsInTransition(0);
        }


        //*********************************************//
        //Help Function
        public IState GetState(Type type)
        {
            if (!StateTable.TryGetValue(type.Name,out var value))
            {
                Debugger.EO_LogError("状态类型不存在缓存:" + type);
            }
            return value;
        }

        public IState GetState(string stateName)
        {
            if (!StateTable.TryGetValue(stateName,out var value))
            {
                Debugger.EO_LogError("状态类型不存在缓存:" + stateName);
            }
            return value;
        }

        public T GetState<T>() where T : class, IState
        {
            return GetState(typeof(T)) as T;
        }

        /// <summary>
        /// 与当前状态进行比较是否为同一状态
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool IsSameStateWithCurrentState(IState other)
        {
            if (!Init) return false;
            if (other == null) return false;
            return other.name == CurrentState.Value.name;
        }
        
        public bool IsSameStateWithCurrentState<T>()where T :class, IState
        {
            if (!Init) return false;
            var other = GetState<T>();
            return IsSameStateWithCurrentState(other);
        }
    }
}
